package Chess.Moves;

import Chess.*;
import Chess.Pieces.*;
import Chess.Pieces.Piece.*;
import java.awt.Color;

/**
 *	A class representing a CastlingMove in Chess.
 *
 *	@author		Jeff Chan
 */
public class CastlingMove extends Move {
	private Piece rook;
	private Square rookStartSquare;
	private Square rookEndSquare;
	
	private CastlingMove(Piece piece, Square startSquare, Square endSquare, Piece rook, Square rookStartSquare, Square rookEndSquare) {
		super(piece, startSquare, endSquare);
		this.rook = rook;
		this.rookStartSquare = rookStartSquare;
		this.rookEndSquare = rookEndSquare;
	}

	public static boolean canBeExecuted(Board board, Square startSquare, Square endSquare) {
		boolean canBeExecuted = false;
				
		Piece king = board.getPiece(startSquare);
		if (king != null && king instanceof King && king.isFirstMove()) {
			int horizontalSquaresMove = endSquare.distanceBetweenFile(startSquare);
			if (endSquare.isInSameRank(startSquare) && Math.abs(horizontalSquaresMove) == 2) {
				char rookFile = (horizontalSquaresMove == 2 ? 'h' : 'a');
				Square rookSquare = new Square(rookFile, startSquare.getRank());
				Piece rook = board.getPiece(rookSquare);
				if (rook != null && rook instanceof Rook && rook.isFirstMove() &&
					board.clearPathBetween(startSquare, rookSquare) &&
					!castlingSquaresInCheck(board, king.getColor(), startSquare, endSquare)) {
					canBeExecuted = true;
				}
			}
		}
		
		return canBeExecuted;
	}

	private static boolean castlingSquaresInCheck(Board board, Color color, Square startSquare, Square endSquare) {
		boolean castlingSquaresInCheck = false;
		
		// Check the Square the King is on now
		if (board.isInCheck(color)) {
			castlingSquaresInCheck = true;
		}
		else {
			// Check the pass-through Square and the end Square
			char fileBetweenStartAndEnd = (endSquare.getFile() > startSquare.getFile() ? 'f' : 'd');
			Square squareBetweenStartAndEnd = new Square(fileBetweenStartAndEnd, startSquare.getRank());
			for (Square square : new Square[] {squareBetweenStartAndEnd, endSquare}) {
				if (!castlingSquaresInCheck && castlingSquareInCheck(board, square, color)) {
					castlingSquaresInCheck = true;
				}
			}
		}
		
		return castlingSquaresInCheck;
	}

	private static boolean castlingSquareInCheck(Board board, Square square, Color color) {
		boolean castlingSquareInCheck = false;
		
		if (!board.hasPiece(square)) {
			// Place a temp Piece on Square so that canAttack evaluates correctly
			Piece tempPiece = new King(color);
			board.putPiece(square, tempPiece);
			if (board.squareInCheck(square, color)) {
				castlingSquareInCheck = true;
			}
		
			// Remove the temp Piece
			board.removePiece(square);
		}
		
		return castlingSquareInCheck;
	}

	public static CastlingMove execute(Board board, Square kingStartSquare, Square kingEndSquare) {
		Square rookStartSquare = null, rookEndSquare = null;
		if (kingEndSquare.distanceBetweenFile(kingStartSquare) == 2) {
			rookStartSquare = new Square('h', kingStartSquare.getRank());
			rookEndSquare = new Square('f', kingStartSquare.getRank());
		} else {
			rookStartSquare = new Square('a', kingStartSquare.getRank());
			rookEndSquare = new Square('d', kingStartSquare.getRank());
		}
		Piece king = board.getPiece(kingStartSquare);
		Piece rook = board.getPiece(rookStartSquare);
		board.movePiece(king, kingStartSquare, kingEndSquare);
		board.movePiece(rook, rookStartSquare, rookEndSquare);
		king.incrementMoveCount();
		rook.incrementMoveCount();
		return new CastlingMove(king, kingStartSquare, kingEndSquare, rook, rookStartSquare, rookEndSquare);
	}
	
	public void undo(Board board) {
		piece.decrementMoveCount();
		rook.decrementMoveCount();
		board.movePiece(piece, endSquare, startSquare);
		board.movePiece(rook, rookEndSquare, rookStartSquare);
	}

	public MoveType getMoveType() {
		return MoveType.CASTLING;
	}

	public Piece getRook() {
		return rook;
	}
	
	public Square getRookStartSquare() {
		return rookStartSquare;
	}
	
	public Square getRookEndSquare() {
		return rookEndSquare;
	}
}
